// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
// File Name:
//
//    USBMON_Bidi_JavaScript_File.js
//
// Abstract:
//
//    Sample USBMON Javascript extension file for v4 printer drivers.
//



/// Base64 Encode from 
///
/// @param  input - binary buffer
///
/// @return String - Encoding Result
///
function Encode64( input )
{
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;
    do {
        chr1 = input[i++];
        chr2 = input[i++];
        chr3 = input[i++];
        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;
        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }
        output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
    } while (i < input.length);
   
    return output;
}

/// Make PJL Command
///
/// @param  Query - PJL String
///
/// @return String - added prefix and postfix data
///
function GetPJLCommand(Query) {
    var Prefix = [0x1B, 0x25, 0x2D, 0x31, 0x32, 0x33, 0x34, 0x35, 0x58, 0x40, 0x50, 0x4A, 0x4C, 0x0D, 0x0A];
    var Postfix = [0x1B, 0x25, 0x2D, 0x31, 0x32, 0x33, 0x34, 0x35, 0x58];

    var Command = Prefix.concat(Query, Postfix);
    return Command;
}

/// Get Attribute data
///
/// @param  Data - Tag String
/// @Param  AttributeName - Name
///
/// @return String - attribute value
///
function GetAttribute(Data, AttributeName) {
    var ret = "";
    var Attributes = Data.split(" ");
    for (i = 0; i < Attributes.length; i++) {
        var Attribute = Attributes[i];
        var Pos = Attribute.indexOf("=");
        if (0 > Pos)
            continue;

        var Tag = Attribute.substring(0, Pos);
        if (Tag === AttributeName) {
            var Data = Attribute.substring(Pos + 1);
            var start = Data.indexOf("\"");
            var end = Data.indexOf("\"", start+1);

            ret = Data.substring(start + 1, end);
            break;
        }
    }
    return ret;
}

/// Parse AutoConfig XML file
///
/// @param  AutoconfigXML - XML data
/// @Param  AttributeName - Name
///
/// @return String - attribute value
///
function ParseAutoConfig(AutoconfigXML, BidiResponses)
{
    var TagStart = 0;
    var TagEnd = 0;
    var Config = "Config";
    var Item = "Item";
    var Xml= AutoconfigXML;
    
    TagStart = Xml.indexOf('<');
    TagEnd = Xml.indexOf('>');

    var Tray2 = "", Tray3 = "", Tray4 = "", Tray5 = "";
    var UsbMemory = false, HardDisk = false, RAMDisk = false;
    var Finisher = false, InnerTray = false;
    var FinisherType = "";

    var subData = "";
    while ((TagStart !== -1) && (TagEnd !== -1)) {
        subData = Xml.substring(TagStart, TagEnd + 1);
        if ((0 <= subData.indexOf(Config)) && (0 <= subData.indexOf('=')))
        {
            var ID = GetAttribute(subData, "ID");
            if (ID === "OptionalTray") {
                TagStart = Xml.indexOf('<', TagEnd + 1);
                TagEnd = Xml.indexOf('>', TagEnd + 1);

                var Items = "";
                var str = Xml.substring(TagStart, TagEnd + 1);
                while (0 <= str.indexOf(Item)) {
                    var Name = GetAttribute(str, "NAME");
                    if ("" !== Name) {
                        var Type = GetAttribute(str, "TRAYTYPE");

                        var Value = "";
                        if (Type === "Standard")    Value = "250";
                        else if (Type === "HighCapacity")   Value = "500";
                        else Value = "";

                        if (Name === "Tray2")
                            Tray2 = Value;
                        else if (Name === "Tray3")
                            Tray3 = Value;
                        else if (Name === "Tray4")
                            Tray4 = Value;
                        else if (Name === "Tray5")
                            Tray5 = Value;
                    }
                    TagStart = Xml.indexOf('<', TagEnd + 1);
                    TagEnd = Xml.indexOf('>', TagEnd + 1);
                    str = Xml.substring(TagStart, TagEnd + 1);
                }
            }
            else if (ID === "OptionalHDD") {
                var Value = GetAttribute(subData, "VALUE");
                if (("0" !== Value) && ("" !== Value))
                    HardDisk = true;
            }
            else if (ID === "RAMDisk") {
                var Value = GetAttribute(subData, "VALUE");
                if (("0" !== Value) && ("" !== Value))
                    RAMDisk = true;
            }
            else if (ID === "InternalUSBMemory") {
                var Value = GetAttribute(subData, "VALUE");
                if (("0" !== Value) && ("" !== Value))
                    UsbMemory = true;
            }
            else if (ID === "Finisher") {
                FinisherType = GetAttribute(subData, "VALUE");
                if ("" !== FinisherType)
                    Finisher = true;
            }
            else if (ID === "OutBin") {
                TagStart = Xml.indexOf('<', TagEnd + 1);
                TagEnd = Xml.indexOf('>', TagEnd + 1);

                var Items = "";
                var str = Xml.substring(TagStart, TagEnd + 1);
                while (0 <= str.indexOf(Item)) {
                    var Name = GetAttribute(str, "NAME");
                    if ("Inner Bin" === Name) {
                        var Value = GetAttribute(str, "VALUE");
                        if ("TRUE" === Value)
                            InnerTray = true;
                    }
                    TagStart = Xml.indexOf('<', TagEnd + 1);
                    TagEnd = Xml.indexOf('>', TagEnd + 1);
                    str = Xml.substring(TagStart, TagEnd + 1);
                }
            }
        }

        TagStart = Xml.indexOf('<', TagEnd + 1);
        TagEnd = Xml.indexOf('>', TagEnd + 1);
    }

    BidiResponses.addString("\\Printer.Configuration.OptionalTray002:Tray2", Tray2);
    BidiResponses.addString("\\Printer.Configuration.OptionalTray003:Tray3", Tray3);
    BidiResponses.addString("\\Printer.Configuration.OptionalTray004:Tray4", Tray4);
    BidiResponses.addString("\\Printer.Configuration.OptionalTray005:Tray5", Tray5);

    BidiResponses.addbool("\\Printer.Configuration.HardDisk:Installed", HardDisk);
    BidiResponses.addbool("\\Printer.Configuration.RamDisk:Installed", RAMDisk);
    BidiResponses.addbool("\\Printer.Configuration.InternalUSBMemory:Installed", UsbMemory);
    
    BidiResponses.addbool("\\Printer.Finishing.Finisher:Installed", Finisher);
    BidiResponses.addbool("\\Printer.Finishing.OptionalInnerBin:Installed", InnerTray);

    return "";
}

/// Read Command from device
///
/// @param  printerStream - Printer stream for communication
/// @Param  Header - Command Header
/// @Param  bufferSize - Minimum Buffer Size
///
/// @return String - read data that exclude Header data.
///
function ReadString(printerStream, Header, bufferSize) {
    var nBufferSize = 50;
    if (bufferSize > nBufferSize)
        nBufferSize = bufferSize;

    var ReadData = "";
    for (var index = 0; index < 3; index++) {
        var readBuffer = printerStream.read(nBufferSize);
        if ((null === readBuffer) || (0 >= readBuffer.length))
            break;

        if (readBuffer.length <= Header.length)
            continue;

        var Data = "";
        for (var i = 0; i < readBuffer.length; i++) {
            Data += String.fromCharCode(readBuffer[i]);
        }

        var nPos = -1;
        if ("" !== Header)
            nPos = Data.search(Header);
            
        if (-1 < nPos) {
            ReadData = Data.substring(Header.length);
            break;
        }
    }
    return ReadData;
}

/// <summary>
///    Get the requested Schema(s).
///
///    The script can use the 'schemaRequests' object to iterate through the Query Keys requested by the user. Based on the query keys,
///    the script should use the 'printerStream' object to communicate with the USB print device and determine the values of one or more Bidi
///    Schema elements. For each Bidi Schema element the new value can be returned to the caller by using functions of the 'printerBidiSchemaResponses'
///    object. Once all query keys have been processed and all values added to the 'printerBidiSchemaResponses' object the script can return.
///
///    It is possible the attached device is not ready to return some of the requested data. In this case the function can return a value of 1 to indicate the call
///    should be retried after a wait.
/// </summary>
/// <param name="scriptContext" type="IPrinterScriptContext">
///     Script context object.
/// </param>
/// <param name="printerStream" type="IPrinterScriptableSequentialStream">
///    Allows the script to Write/Read data from the attached USB device.
/// </param>
/// <param name="schemaRequests" type="Array">
///    Array of strings that contains all the requested Query Keys.
/// </param>
/// <param name="printerBidiSchemaResponses" type="IPrinterBidiSchemaResponses">
///    Object the script will use to store all responses to query keys.
/// </param>
/// <returns type="Number" integer="true">
///     Integer value indicating function completion status.
///         1 - The attached device was not ready to provide some requested information. Call the function again using any Requery Keys added during processing.
///         0 - The script completed successfuly.
/// </returns>
function getSchemas( scriptContext, printerStream, schemaRequests,  printerBidiSchemaResponses ) 
{
    var retVal = 0;
    var i = 0;

    debugger;

    var bag = scriptContext.QueueProperties;
    var queueProperty = bag.GetString("Config:Win8Support");
    
    //Loop through all the QueryKeys provided in the schemaRequests object
    for ( var index = 0; index < schemaRequests.length; index++ ) {
        var key = schemaRequests[index];  
        
        if (("On" !== queueProperty) && ("DEVICEID" !== key)) {
            if ("Off" !== queueProperty)  {
                retVal = 1;
                printerBidiSchemaResponses.addRequeryKey(key);
            }
            continue;
        }
        
        if (key === "DEVICEID") {
            //Request:  @PJL INFO ID
            //Response: @PJL INFO ID\n"Samsung ML-375x Series"
            var bId = false;
            var Id = "";
            var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x49, 0x4E, 0x46, 0x4F, 0x20, 0x49, 0x44, 0x0D, 0x0A];
            var writeData = GetPJLCommand(Data);
            var bytesWritten = printerStream.write(writeData);
            if (bytesWritten === writeData.length) {
                var result = ReadString(printerStream, "@PJL INFO ID", 128);
                if ("" !== result) {
                    var nStart = result.indexOf('\"');
                    var nEnd = result.lastIndexOf('\"');
                    Id = result.substring(nStart+1, nEnd);
                    if ("" !== Id)
                        bId = true;
                }
            }
            if (false === bId) {
                continue;
            }

            printerBidiSchemaResponses.addString("\\Printer.DeviceInfo:Id", Id);

            //Request:  @PJL GETDEVICEID
            //Response: @PJL GETDEVICEID "deviceid.."
            var bDeviceId = false;
            var DeviceId = "";
            var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x47, 0x45, 0x54, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x49, 0x44, 0x0D, 0x0A];
            var writeData = GetPJLCommand(Data);
            var bytesWritten = printerStream.write( writeData );
            if (bytesWritten === writeData.length) {
                var result = ReadString(printerStream, "@PJL GETDEVICEID=", 512);
                DeviceId = result.replace(/\"/g, '');
                if ("" !== DeviceId)
                {
                    bDeviceId = true;
                    if (-1 < DeviceId.search(/win8/i))
                        printerBidiSchemaResponses.addBool("\\Printer.Samsung.AutoConfiguration:Supported", true);
                }
            }
            if (false === bDeviceId) {
                if (bId)
                    printerBidiSchemaResponses.addBool("\\Printer.Samsung.AutoConfiguration:Supported", false);
            }

            printerBidiSchemaResponses.addString("\\Printer.DeviceInfo:DeviceId", DeviceId);
            
        }
        else if (key === "DEVICEIMAGE") {
            //Request:  1B 91 00 00 00 00 00 03 00 00 00 01 00 00 00 00
            //Response: 1B 91 00 00 00 00 00 03 00 00 00 01 01 12 24 33
            //          Image data
            var ImageData = "";
            var writeData = [0x1B, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00];
            var bytesWritten = printerStream.write(writeData);
            if (bytesWritten === writeData.length) {
                for (i = 0; i < 3; i++) {
                    var readBuffer = printerStream.read(50);
                    if ((null === readBuffer) || (0 === readBuffer.length))
                        break;

                    if (readBuffer.length == 16) {
                        if ((readBuffer[0] !== 0x1B) || (readBuffer[1] !== 0x91))
                            continue;

                        var size = 0;
                        for (i = 0; i < 4; i++) {
                            size *= 256;
                            size += readBuffer[12 + i];
                        }
                        if (size > 0) {
                            var readBuffer2 = printerStream.read(size);
                            if ((null != readBuffer2) && (readBuffer2.length === size)) {
                                ImageData = Encode64(readBuffer2);
                            }
                        }
                        break;
                    }
                }
            }
            printerBidiSchemaResponses.addString("\\Printer.DeviceInfo:Image", ImageData);
        }
        //else if (key === "AUTOCONFIG_COUNTER")  {
        //    //Request:  @PJL AUTOCONFIG_COUNTER
        //    //Response: @PJL AUTOCONFIG_COUNTER 0000...001
        //    var bCounter = false;
        //    var Counter = 0;
        //    var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x41, 0x55, 0x54, 0x4F, 0x43, 0x4F, 0x4E, 0x46, 0x49, 0x47, 0x5F, 0x43, 0x4F, 0x55, 0x4E, 0x54, 0x45, 0x52, 0x0D, 0x0A];
        //    var writeData = GetPJLCommand(Data);
        //    var bytesWritten = printerStream.write( writeData );
        //    if (bytesWritten === writeData.length) {
        //        var readBuffer = printerStream.read(128);
        //        var Header = "@PJL AUTOCONFIG_COUNTER ";
        //        if ((null !== readBuffer) && (readBuffer.length > Header.length)) {
        //            var first = Header.length;
        //            for (i = 0; i < readBuffer.length - first; i++)
        //            {
        //                Counter *= 256;
        //                Counter += readBuffer[first + i];
        //            }
        //            bCounter = true;
        //        }
        //    }
        //    if (false === bCounter) {
        //        retVal = 1;
        //        printerBidiSchemaResponses.addRequeryKey("AUTOCONFIG_COUNTER");
        //    }
        //    printerBidiSchemaResponses.addInt32("\\Printer.Samsung.AutoConfiguration:Counter", Counter);
        //}
        else if (key === "AUTOCONFIG_DATA") {
            //Request:  @PJL AUTOCONFIG
            //Response: @PJL AUTOCONFIG <xml> .....</xml>
            var AutoConfigXml = "";
            var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x41, 0x55, 0x54, 0x4F, 0x43, 0x4F, 0x4E, 0x46, 0x49, 0x47, 0x0D, 0x0A];
            var writeData = GetPJLCommand(Data);
            var bytesWritten = printerStream.write( writeData );
            if (bytesWritten === writeData.length) {
                AutoConfigXml = ReadString(printerStream, "@PJL AUTOCONFIG ", 10240);
                if ("" !== AutoConfigXml) {
                    ParseAutoConfig(AutoConfigXml, printerBidiSchemaResponses);
                }
            }
            printerBidiSchemaResponses.addString("\\Printer.Samsung.AutoConfiguration:Data", AutoConfigXml);
        }
        else if (key === "LITESM_SPEC") {
            //Request:  @PJL LITESMSPEC
            //Response: @PJL LITESMSPEC <xml> .....</xml>
            var SpecXml = "";
            var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x4C, 0x49, 0x54, 0x45, 0x53, 0x4D, 0x53, 0x50, 0x45, 0x43, 0x0D, 0x0A];
            var writeData = GetPJLCommand(Data);
            var bytesWritten = printerStream.write( writeData );
            if (bytesWritten === writeData.length) {
                SpecXml = ReadString(printerStream, "@PJL LITESMSPEC ", 102400);
            }
            printerBidiSchemaResponses.addString("\\Printer.Samsung.LiteSM:Specification", SpecXml);
        }
        else if (key === "LITESM_CAP") {
            var CapData = "";
            //Request:  1B 24 F4 00 00 00 00 00 00 00
            //Response: 1B 24 F4 00 00 00 00 01 24 13
            var writeData = [ 0x1B, 0x24, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
            var bytesWritten = printerStream.write( writeData );
            if (bytesWritten === writeData.length) {
                for (i = 0; i < 3; i++) {
                    var readBuffer = printerStream.read(50);
                    if ((null === readBuffer) || (0 === readBuffer.length))
                        break;

                    if (readBuffer.length === 10) {
                        if ((readBuffer[0] !== 0x1B) || (readBuffer[1] !== 0x24) || (readBuffer[2] !== 0xF4))
                            continue;

                        var Size = 0;
                        for (i = 0; i < 4; i++) {
                            Size *= 256;
                            Size += readBuffer[6 + i];
                        }
                        //Request:  1B 24 F4 01 00 00 00 00 00 00
                        //Response: <xml>.....</xml>
                        var writeData2 = [0x1B, 0x24, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
                        var byteWritten2 = printerStream.write(writeData2);
                        if (byteWritten2 === writeData2.length) {
                            var readBuffer2 = printerStream.read(Size);
                            if ((null !== readBuffer2) && (readBuffer2.length === Size)) {
                                for (i = 0; i < readBuffer2.length; i++) {
                                    CapData += String.fromCharCode(readBuffer2[i]);
                                }
                            }
                        }
                        break;
                    }
                }
            }
            printerBidiSchemaResponses.addString("\\Printer.Samsung.LiteSM:Capability", CapData);
        }
        else if (key === "LITESM_STATUS") {
            //Request:  @PJL LITESMSTATUS
            //Response: @PJL LITESMSTATUS STATUSCODE=0401020354FFFFFF
            var SMStat = "";
            var Data = [0x40, 0x50, 0x4A, 0x4C, 0x20, 0x4C, 0x49, 0x54, 0x45, 0x53, 0x4D, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x0D, 0x0A];
            var writeData = GetPJLCommand(Data);
            var bytesWritten = printerStream.write(writeData);
            if (bytesWritten === writeData.length) {
                SMStat = ReadString(printerStream, "@PJL LITESMSTATUS STATUSCODE=", 45);
            }
            printerBidiSchemaResponses.addString("\\Printer.Samsung.LiteSM:Status", SMStat);
        }
        /*else if (key === "STATUS") {
            //Request:  @PJL DRIVERSTATUS
            //Response: @PJL DRIVERSTATUS STATUSCODE=010001
            var Stat = 0;
            var writeData = [ 0x40, 0x50, 0x4A, 0x4C, 0x20, 0x44, 0x52, 0x49, 0x56, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53 ];
            var bytesWritten = printerStream.write(writeData);
            if (bytesWritten === 17) {
                var readBuffer = printerStream.read(32);
                if ( readBuffer.length === 32 ) {
                    for (i = 1; i <= readBuffer.length - bytesWritten - 12; i++) {
                        Stat += String.fromCharCode(readBuffer[28 + i]);
                    }
                    retVal = 1;
                }
            }
            printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", Stat);
        }*/
    }
    return retVal;
}

///
/// Set a requested Bidi Schema Value in the device
///
/// @param  scriptContext - Script context object which allows access to IPrinterScriptablePropertyBag for printer driver and queue properties
/// @param  printerStream - Allows the script to Write/Read data from the attached USB device
/// @param  printerBidiSchemaElement - Contains all the data associated with the Bidi Schema Value to set
/// 
/// @return Integer value - currently only JavaScript exceptions are expected for failures
///
/// The script can interpret the incoming Bidi Schema value to either set data in the device or perform an action on the device. 
///
/// The scriptContext object provides access to the Driver and Queue prorperty bags associated with the current device. These property bags support read-only access.
/// 
function setSchema( scriptContext, printerStream, printerBidiSchemaElement ) 
{ 
    return 0;
}

/// <summary>
///    Retrieve unsolicited Bidi Schema value updates from the USB device during printing.
///
///    This function is only called when a job is printing. A device can provide data on the read channel which this script can interpret into
///    Bidi Schema values and returned to USBMon.
///
///    This function will be called repeatedly during printing. It is expected the device will only return data if it is available and the script can understand it.
///    If the device does not support querying for unsolicited status or the script can determine that there is no need to call this function again, the script can return
///    a value of 2 which will tell the getStatus execution thread in USBMon to exit successfully.
///
///    If the print device does not support retrieving status during a print job this function should be left out of the driver's JavaScipt file altogether. This will inform 
///    USBMon to skip invocation of the function.
/// </summary>
/// <param name="scriptContext" type="IPrinterScriptContext">
///    Accessor for PropertyBags for printer driver and queue properties.
/// </param>
/// <param name="printerStream" type="IPrinterScriptableSequentialStream">
///    Allows the script to read data from the attached USB device. Calling the write function will fail. This device is opened read-only for this function.
/// </param>
/// <param name="printerBidiSchemaResponses" type="IPrinterBidiSchemaResponses">
///    Object the script will use to store all status responses.
/// </param>
/// <returns type="Number" integer="true">
///     Integer value indicating function completion status.
///         2 - The device no longer (if ever) supports unsolicited status so no need for USBMon to make more calls to this function.
///         0 - The script completed successfuly.
/// </returns>
function getStatus( scriptContext, printerStream, printerBidiSchemaResponses ) 
{ 
    var retVal = 0;
   
    debugger;
    
    var bag = scriptContext.QueueProperties;
    var queueProperty = bag.GetString("Config:Win8Support");
    if ("Off" === queueProperty) {
        return 2;
    }

    //sample: @PJL DRIVERSTATUS STATUSCODE=00040002
    var bReadStatus = false;
    var readBuffer = printerStream.read(50);
    if (null !== readBuffer) {
        var bytesRead = readBuffer.length;
        var Header = "@PJL DRIVERSTATUS STATUSCODE=";

        if (bytesRead > Header.length) {
            var Read = "";
            for (i = 0; i < bytesRead; i++)
                Read += String.fromCharCode(readBuffer[i]);

            if (-1 < Read.search(Header)) {
                var Category = Read.substr(Header.length, 4).toUpperCase();
                var Status = Read.substr(Header.length + 4, 4).toUpperCase();

                if (Category === "0001") {      //None
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "None");
                }
                else if (Category === "0002") { //Door
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "DoorOpen");
                }
                else if (Category === "0003") { //Marker
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MarkerSupplyLow");
                    else if (Status === "0002")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MarkerFailure");
                    else if (Status === "0003")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MarkerSupplyEmpty");
                }
                else if (Category === "0004") { //Media
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MediaLow");
                    else if (Status === "0002")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MediaEmpty");
                    else if (Status === "0003")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MediaJam");
                    else if (Status === "0004")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "MediaNeeded");
                }
                else if (Category === "0005") { //Output
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "OutputAreaAlmostFull");
                    else if (Status === "0002")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "OutputAreaFull");
                }
                else if (Category === "F000") { //AttentionRequired
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "AttentionRequired");
                }
                else if (Category === "F100") { //Paused
                    if (Status === "0001")
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "Paused");
                }
                else if (Category === "FFFF") { //Job End
                    if (Status === "FFFF") {
                        printerBidiSchemaResponses.addString("\\Printer.Status.Summary:StateReason", "None");
                        retVal = 2;
                    }
                }

                bReadStatus = true;
            }
        }
    }
    
    if ("None" === queueProperty) {
        if (bReadStatus) {
            printerBidiSchemaResponses.addBool("\\Printer.Samsung.AutoConfiguration:Supported", true);
        }
        else {
            printerBidiSchemaResponses.addBool("\\Printer.Samsung.AutoConfiguration:Supported", false);
            retVal = 2;
        }
    }
    
   return retVal;
}
